定位一次 tomcat catelina.out 日志文件过大的问题

  • catalina.out过大的定位过程&解决方案

场景记录

在一次mysql create table失败问题定位过程中,发现exitcode是28,即磁盘写失败导致的。可以参见这里df -hk的查看结果是mysql所在分区100%usage。

问题定位过程

找到大文件

首先需要找到问题原因,即被什么文件吃满了disk。

du -sh / | sort -h

一直分析下去,可以定位到原因是catalina.out & flume的log比较大。

什么内容写入到catalina.out

catalina.out文件是tomcat的默认log方式,采用的是java.util.logging.Logging来控制的。其配置文件是:

[root@test-239 logs]# ps aux | grep java | grep logging
root     27130  0.9 12.4 4780116 998124 ?      Sl   04:01   4:42 java -Djava.util.logging.config.file=/usr/local/ahiddenpath/apache-tomcat-7.0.64/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.security.egd=file:/dev/./urandom -Djava.endorsed.dirs=/usr/local/ahiddenpath/apache-tomcat-7.0.64/endorsed -classpath /usr/local/ahiddenpath/apache-tomcat-7.0.64/bin/bootstrap.jar:/usr/local/ahiddenpath/apache-tomcat-7.0.64/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/ahiddenpath/apache-tomcat-7.0.64 -Dcatalina.home=/usr/local/ahiddenpath/apache-tomcat-7.0.64 -Djava.io.tmpdir=/usr/local/ahiddenpath/apache-tomcat-7.0.64/temp org.apache.catalina.startup.Bootstrap start

据上可知,配置文件在/usr/local/ahiddenpath/apache-tomcat-7.0.64/conf/logging.properties,查看其中内容:

handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler

其中:

  • FileHandler:输出log到指定文件
  • ConsoleHandler:输出log到console

在写demo验证logging.properties配置项的时候发现:

  • java project默认是使用jre lib中的配置
  • path一般是jre/lib下面的logging.properties

这个确实比较坑,改了半天配置都不生效,具体可以戳这里

另外一个比较蠢萌的点,是 -Djava.util.logging.config.file指定logging.properties位置的时候,-D需要在被运行的类之前,如:

  • 这样是对的:java -Dxxx class
  • 这样是无效的:java class -Dxxx

除了catalina.out,tomcat还有什么其他日志

在看到文章:

之后,对其中提到的 tomcat 的几种 log 做个总结:

  • log 类型是
    • catalina.out
    • cataliana.{yyyy-MM-dd}.log
    • localhost.{yyyy-MM-dd}.log
    • manager.{yyyy-MM-dd}.log
    • host-manager.{yyyy-MM-dd}.log
  • tomcat 可以改用log4j
  • console的内容会输出到 catalina.out,即System.out.println()

更多的详细信息还是参见上面的三篇文档。

如何解决问题

为了避免这个问题,两种思路去限制:

  • 修改配置本身不输出到catalina.out
  • 限制catalina.out的输出:log rotate

log rotate

是由cron触发的,定期执行的log切分程序。与log4j的文件拆分是有区别的,比如无法设置文件大小上限

具体学习的话,可以参考文档:

  • logrotate的机制与原理
    • 戳这里
    • 核心内容:
      • cron触发:/etc/cron.daily/logrotate
      • 自定义在/etc/logrotate下面的conf,是通过/etc/logrotate.conf中的include /etc/logrotate.d来触发的
      • 另外文中还比较了create和copytruncate方案的原理
  • log rotate sample

修改logging配置文件

很简单,删除 ${catalina.base}/conf下面的logging.properties中的handlers= java.util.logging.ConsoleHandler即可。

这里举例是针对tomcat默认的logging.properties的位置,具体到其他项目,请具体查看-Djava.util.logging.config.file的值

通过简单代码例子可知:

测试类代码:

package demo.maven;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * java util logging的测试类.
 * @author liruifeng
 * @see JavaUtilLoggingTest
 */
public class JavaUtilLoggingTest {

    private static final Logger logger = Logger.getLogger(JavaUtilLoggingTest.class.getName());

    public static void main(String args[]) {
        System.out.println(System.getProperty("java.util.logging.config.file"));
        System.out.println(System.getProperty("sss"));
        // Handler consoleHandler = new ConsoleHandler();
        // consoleHandler.setLevel(Level.ALL);
        // Logger.getAnonymousLogger().addHandler(consoleHandler);
        logger.setLevel(Level.ALL);
        System.out.println(logger.getLevel());
        logger.log(Level.ALL, "Level.ALL");
        logger.log(Level.FINE, "Level.FINE");
        logger.fine("fine");
        logger.log(Level.FINER, "Level.FINER");
        logger.log(Level.FINEST, "Level.FINEST");
        logger.log(Level.CONFIG, "Level.CONFIG");
        logger.log(Level.INFO, "Level.INFO");
        logger.info("info");
        logger.log(Level.WARNING, "Level.WARNING");
        logger.log(Level.SEVERE, "Level.SEVERE");
        logger.log(Level.OFF, "Level.OFF");
    }
}

原logging.properties(部分,在$jre_path/lib下面):

handlers=java.util.logging.ConsoleHandler

output:

null
null
ALL
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
全部: Level.ALL
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
详细: Level.FINE
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
详细: fine
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
较详细: Level.FINER
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
非常详细: Level.FINEST
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
配置: Level.CONFIG
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
信息: Level.INFO
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
信息: info
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
警告: Level.WARNING
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
严重: Level.SEVERE
五月 26, 2017 4:48:48 下午 demo.maven.JavaUtilLoggingTest main
禁用: Level.OFF

修改后的logging.properties

#handlers=java.util.logging.ConsoleHandler

对应output:

null
null
ALL

以上,测试生效